package com.zhang.handler;

import cn.hutool.core.util.StrUtil;
import com.zhang.ClientChannelManage;
import com.zhang.HttpChannelManage;
import com.zhang.common.Constant;
import com.zhang.common.codec.MyHttpResponseEncoder;
import com.zhang.common.config.GlobalConfig;
import com.zhang.common.message.ProxyMessage;
import com.zhang.common.message.ProxyMessageUtil;
import com.zhang.event.TransferSuccess;
import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.handler.codec.http.DefaultFullHttpResponse;
import io.netty.handler.codec.http.HttpHeaderNames;
import io.netty.handler.codec.http.HttpResponseStatus;
import io.netty.handler.codec.http.HttpVersion;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.ArrayList;
import java.util.List;

/**
 * 自定义协议处理器类
 * @author zhanghao
 */
public class ServerHandler extends ChannelInboundHandlerAdapter {

    /**
     * 日志对象
     */
    static private Logger log = LoggerFactory.getLogger(ServerHandler.class);

    private MyHttpResponseEncoder encoder = new MyHttpResponseEncoder();

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object ob)  {
        try{
            ProxyMessage proxyMessage = (ProxyMessage) ob;
            Byte msgType = proxyMessage.getMsgType();
            Long httpId = proxyMessage.getHttpId();
            switch (msgType) {
                case Constant.MessageType.TYPE_REGISTER_REQUEST:
                    //注册事件
                    //域名
                    String domain = proxyMessage.getDomain();
                    log.debug("{} 域名注册...",domain);
                    //域名校验
                    if (!StrUtil.isBlank(domain)){
                        Channel channelByDomain = ClientChannelManage.getChannelByDomain(domain);
                        if(null != channelByDomain){
                            //协议实体
                            //发送  注册失败消息
                            ctx.writeAndFlush(
                                    ProxyMessageUtil.buildRegisterRespFail(Constant.RegisterFailCodeType.DOMAIN_EXIST)
                            );
                            return;
                        }
                        log.info("{} 注册成功",domain);
                        //添加域名跟channel映射关系
                        ClientChannelManage.addDomainAndChannel(domain,ctx.channel());
                        //注册结果返回
                        ctx.writeAndFlush(
                                ProxyMessageUtil.buildRegisterRespSuccess(GlobalConfig.props.getInt("httpPort"))
                        );

                    }else{
                        ctx.writeAndFlush(
                                ProxyMessageUtil.buildRegisterRespFail(Constant.RegisterFailCodeType.DOMAIN_EXIST)
                        );
                        return;
                    }
                    break;
                case Constant.MessageType.TYPE_CONNECT_REAL_SERVER_RESPONSE_SUCCESS:
                    Channel channelSuccess = HttpChannelManage.getChannelById(httpId);
                    if(null != channelSuccess){
                        //通知 httpServerHandler可以发送http数据了
                        log.debug("触发转发请求事件");
                        channelSuccess.pipeline().fireUserEventTriggered(new TransferSuccess());
                        channelSuccess.config().setAutoRead(true);
                    }
                    break;
                case Constant.MessageType.TYPE_CONNECT_REAL_SERVER_RESPONSE_FAIL:

                    log.info("连接真实服务器失败");
                    sendFailMsg(ctx, httpId);
                    break;
                case Constant.MessageType.TYPE_TRANSFER_RESPONSE_SUCCESS:
                    //响应数据 http的id

                    Channel channel = HttpChannelManage.getChannelById(httpId);
                    if(null != channel){

                        byte[] bytes = proxyMessage.getData();
                        channel.writeAndFlush(Unpooled.wrappedBuffer(bytes));
                        log.debug("推送给浏览器真实服务器的响应");
                    }

                    break;
                case Constant.MessageType.TYPE_TRANSFER_RESPONSE_FAIL:
                    //转发到真实服务器失败
                    log.error("转发到真实服务器失败");
                    sendFailMsg(ctx, httpId);
                    break;

                default:
                    log.error("未知的消息类型 {}",msgType);
                    break;
            }
        }catch (Exception e){
            log.error("接收真实服务器响应失败",e);
        }

    }

    /**
     * 发送失败消息 给 浏览器
     * @param ctx
     * @param httpId
     * @throws Exception
     */
    private void sendFailMsg(ChannelHandlerContext ctx, Long httpId) throws Exception {
        Channel channelFail = HttpChannelManage.getChannelById(httpId);
        if(null != channelFail){
            DefaultFullHttpResponse response =
                    new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.NOT_FOUND);
            response.headers().set(HttpHeaderNames.CONTENT_TYPE,"text/html;charset=utf-8");
            response.content().writeBytes("真实服务器未开启".getBytes());

            List<Object> list = new ArrayList<>();
            encoder.encode(ctx,response,list);
            for (Object o:list){
                channelFail.writeAndFlush(o).addListener(ChannelFutureListener.CLOSE);
            }
        }
    }
}
